#ifndef TH_H_
#define TH_H_
#include "conf.h"

C_CODE_BEGIN

#ifdef __linux__
#include <pthread.h>
#elif _WIN32
#include <process.h>
#include <windows.h>
#else
#endif


#ifdef __linux__
typedef pthread_t thread_handler;
typedef unsigned int thread_id;
#elif _WIN32
typedef void* thread_handler; 
typedef DWORD thread_id;
#else
#endif 

typedef void* (*thread_cb)( void* par );

struct th_join_sec {
	size_t sec ;
	size_t micro_sec;
};

#define MAKE_TH_JOIN_SEC_ZERO( tjs ) \
	tjs.sec = 0 ; tjs.micro_sec =0

/*
* this function will create a thread based on the platform
* thread handler is a platform unique identifier for identifying
* the thread , the thread_cb is a callback for this thread when
* it executes . The thread MUST EXIT by its own , instead of relaying on
* other termination signal. 
* The thread does not support the priority since it first of all , is useless
* in many situation unless in terms of specific context , second , it can not
* implement between different platform. 
*/

EXPORT_FUNC bool thread_create( thread_handler* handler , const char* name , thread_cb cb  , void* par ,  bool detach ) ;


/*
* Join operation . Join operation allows you to join the thread until it finished , this is typically
* the most safe way , if the thread has been specified to detach , then this thread will not need to
* be joined ,all its related resource will be released until it finished. If the minisec has been specified
* as none negative , the thread_join will try to join the thread until the minisec elapsed ; if the minisec
* has been set to zero , the thread_join will try to join it once and return the status immediately , otherwise
* the thread_join will join permanently.
*/

EXPORT_FUNC bool thread_join( thread_handler handler , void** return_val , const struct th_join_sec * ti );

/*
* get the current thread handler value
*/

EXPORT_FUNC thread_id thread_current();

/*
* yield to another thread
*/
EXPORT_FUNC void thread_yield();
/*
* sleep the current thread
*/

EXPORT_FUNC void thread_sleep( const struct th_join_sec* sec );
  
	/*
   * Lock type definition
   */
   
#ifdef __linux__
typedef pthread_mutex_t fastlock;
#elif _WIN32
typedef CRITICAL_SECTION fastlock;
#else
#endif
	
/*
 * This function will create a fastlock on the platform , this creation will make the fastlock a "NON-RECURSIVE" lock.
 * In debug version ,this lock may spawn assertion which typically is good for detecting recursive calling of this function.
 */
EXPORT_FUNC void thread_fastlock_create( fastlock* fl );

/*
 * This function will destroy the lock 
 */
EXPORT_FUNC void thread_fastlock_destroy( fastlock* fl );

/*
 *This function will obtain the lock otherwise wait until it is available.
 * The second parameter will set the locking time , if it is NULL value ,means
 * this function will just wait permanently until it is available , otherwise
 * if the sec set to zero ( which means the low and high part are both zero )
 * the function will just try to obtain the fastlock , otherwise a real time wait
 * will be performed.
 */
 
EXPORT_FUNC bool thread_fastlock_require( fastlock* fl , const struct th_join_sec* ti );
 
 /*
  *This function will release the fastlock
  */
  
EXPORT_FUNC void thread_fastlock_release( fastlock* fl );
	  
	  
#ifdef __linux__
typedef pthread_spinlock_t spinlock;
#elif _WIN32
/*
 * Since win32 does not have default spinlock supported
 * I gonna make a tiny spinlock using InterlockXXX function
 */
#ifdef WIN32_ENABLE_CRITICAL_SECTION_AS_SPINLOCK
typedef CRITICAL_SECTION spinlock;
#else
typedef LONG volatile spinlock;
#endif

#else
#endif

EXPORT_FUNC void thread_spinlock_create( spinlock* sp );
EXPORT_FUNC void thread_spinlock_destroy( spinlock* sp );
EXPORT_FUNC bool thread_spinlock_require( spinlock* sp , bool once );
EXPORT_FUNC void thread_spinlock_release( spinlock* sp );

	
	
#ifdef __linux__
typedef pthread_cond_t event;
#elif _WIN32

/*
 * Windows has built-in condition variable when the windows release its Vista , so the condition variable is not
 * supported by Windows XP as well as Windows Server 2003.
 * In fact I can use a event to simulate the pthread_cond_singal , however the pthread_cond_braodcast is quit hard
 * to simulate on windows ,so such feature on windows is postpone . 
 * We will use Conditional Variable on windows for simplicity , and code a substitution using Event later .
 */
#ifdef WIN32_ENABLE_BUILT_IN_CONDITION_VARIABLE
typedef CONDITION_VARIABLE event;
#else
#error "The alternative condition variable on windows is not implemented yet"
#endif

#else
#endif

EXPORT_FUNC void thread_event_create( event* eve );
EXPORT_FUNC void thread_event_destroy( event* eve );
EXPORT_FUNC bool thread_event_wait( event* eve , fastlock* fl , const struct th_join_sec* ti);
/*
 * The signal function will just put ONE thread in the queue and resume it
 */
EXPORT_FUNC void thread_event_signal( event* eve );
/*
 * The broadcast function will resume all the thread in the queue
 */
EXPORT_FUNC bool thread_event_broadcast( event* eve );

#ifdef __linux__
typedef pthread_key_t tls;
#elif _WIN32
typedef DWORD tls;
#else
#endif
	
EXPORT_FUNC void thread_tls_create( tls* t );
EXPORT_FUNC void thread_tls_destroy( tls t );
EXPORT_FUNC void thread_tls_set( tls t , void* var );
EXPORT_FUNC void thread_tls_get( tls t , void** varp );


C_CODE_END

#endif // TH_H_